import router from "@/router";
import store from "@/store";
import {_, createUUID} from "@/utils/common.util";
import {Instance} from "@/utils/project.util";

export class BackInvoke {
    constructor(funcName, params, delay) {
        this.funcName = funcName;
        this.params = params;
        this.delay = delay;
    }

    funcName = '';
    delay = 0;
    params = [];
}

export class WaitForTask {
    constructor(id, task) {
        this.id = id;
        this.task = task;
    }

    id = '';
    task = null;
}

export const Events = {
    /** @type BackInvoke **/
    backInvoke: null,
    addBackInvoke(funcName, ...params) {
        this.backInvoke = new BackInvoke(funcName, params);
    },
    clearBackInvoke() {
        this.backInvoke = null;
    },
    waitForTasks: [],
    addWaitTask(task) {
        let waitForTask = new WaitForTask(createUUID(), task);
        this.waitForTasks.push(waitForTask);
        return waitForTask;
    },
    removeWaitTask(taskOrId) {
        if (!taskOrId) return this.waitForTasks = [];
        if (taskOrId instanceof WaitForTask) {
            let index = this.waitForTasks.findIndex( task => task === taskOrId );
            if( index >= 0 ) this.waitForTasks.splice( index, 1 );
            return ;
        }
        let index = this.waitForTasks.findIndex(({id}) => id === taskOrId );
        if( index >= 0 ) this.waitForTasks.splice(index,1);
    },
    invokeWaitTask(all = false) {
        if (!this.waitForTasks.length) return false;
        if (!all) {
            let {task} = this.waitForTasks.pop();
            task && task();
        }
        else {
            this.waitForTasks.forEach(({task}) => task && task());
            this.removeWaitTask();
        }
        return true;
    }
};


export const Navigate = {

    install(Vue) {
        Vue.prototype.$navigate = this;
    },

    to(path, options = {}, isBack = false) {
        if (Events.invokeWaitTask()) return;
        store.commit('layout/setNavigateDirect', isBack ? -1 : 1);
        router.push({path, ...options});
    },

    toParams(path, params = {}) {
        this.to(path, {params});
    },

    toQuery(path, query = {}) {
        this.to(path, {query});
    },

    back(options = {}) {
        if (Events.invokeWaitTask()) return;
        if (options.backInvoke) {
            Events.addBackInvoke(options.backInvoke.funcName, ...options.backInvoke.params);
        }
        if (options.skip) {
            this.backInvoke('BACK_SKIP', ... options.skip);
        }
        window.history.go(-1);
    },

    backSkip( ... params ) {
        this.back({skip: params });
    },

    backInvoke(funcName, ...params) {
        this.back({backInvoke: {funcName, params}});
    },
};
